home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 003 / _gs / !GS / c / GSCOLOR < prev    next >
Text File  |  1991-10-26  |  11KB  |  381 lines

  1. /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gscolor.c */
  21. /* Color and halftone operators for GhostScript library */
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gxfixed.h"            /* ditto */
  25. #include "gxmatrix.h"            /* for gzstate.h */
  26. #include "gxdevice.h"            /* for gx_color_index */
  27. #include "gzstate.h"
  28. #include "gzcolor.h"
  29. #include "gzht.h"
  30.  
  31. /* Exported values */
  32. const uint gs_screen_enum_sizeof = sizeof(gs_screen_enum);
  33. const uint gs_color_sizeof = sizeof(gs_color);
  34.  
  35. /* Forward declarations */
  36. private void tri_param(P4(floatp, floatp, floatp, color_param [3]));
  37. private void tri_return(P4(color_param, color_param, color_param, float [3]));
  38. private void set_phase(P1(gs_state *));
  39. /* Imported from gxcolor.c */
  40. void    gx_set_gray_only(P2(gs_color *, floatp)),
  41.     gx_set_rgb_only(P4(gs_color *, floatp, floatp, floatp));
  42. float    gx_unit_param(P1(floatp));
  43. void    gx_color_from_hsb(P4(gs_color *, color_param, color_param, color_param)),
  44.     gx_color_from_rgb(P1(gs_color *)),
  45.     gx_color_to_hsb(P2(gs_color *, color_param [3])),
  46.     gx_sort_ht_order(P2(ht_bit *, uint));
  47.  
  48. /* setgray */
  49. int
  50. gs_setgray(gs_state *pgs, floatp gray)
  51. {    if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  52.     gx_set_gray_only(pgs->color, gray);
  53.     return gx_remap_color(pgs);
  54. }
  55.  
  56. /* currentgray */
  57. float
  58. gs_currentgray(gs_state *pgs)
  59. {    return (float)(color_luminance(pgs->color) / (float)max_color_param);
  60. }
  61.  
  62. /* setgscolor */
  63. int
  64. gs_setgscolor(gs_state *pgs, gs_color *pcolor)
  65. {    if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  66.     *pgs->color = *pcolor;
  67.     return gx_remap_color(pgs);
  68. }
  69.  
  70. /* currentgscolor */
  71. int
  72. gs_currentgscolor(gs_state *pgs, gs_color *pcolor)
  73. {    *pcolor = *pgs->color;
  74.     return 0;
  75. }
  76.  
  77. /* sethsbcolor */
  78. int
  79. gs_sethsbcolor(gs_state *pgs, floatp h, floatp s, floatp b)
  80. {    color_param params[3];
  81.     if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  82.     tri_param(h, s, b, params);
  83.     gx_color_from_hsb(pgs->color, params[0], params[1], params[2]);
  84.     return gx_remap_color(pgs);
  85. }
  86.  
  87. /* currenthsbcolor */
  88. int
  89. gs_currenthsbcolor(gs_state *pgs, float pr3[3])
  90. {    color_param hsb[3];
  91.     gx_color_to_hsb(pgs->color, hsb);
  92.     tri_return(hsb[0], hsb[1], hsb[2], pr3);
  93.     return 0;
  94. }
  95.  
  96. /* setrgbcolor */
  97. int
  98. gs_setrgbcolor(gs_state *pgs, floatp r, floatp g, floatp b)
  99. {    if ( pgs->in_cachedevice ) return_error(gs_error_undefined);
  100.     gx_set_rgb_only(pgs->color, r, g, b);
  101.     return gx_remap_color(pgs);
  102. }
  103.  
  104. /* currentrgbcolor */
  105. int
  106. gs_currentrgbcolor(gs_state *pgs, float pr3[3])
  107. {    gs_color *pcolor = pgs->color;
  108.     tri_return(pcolor->red, pcolor->green, pcolor->blue, pr3);
  109.     return 0;
  110. }
  111. /* A special entry for makeimagedevice, for converting the palette. */
  112. int
  113. gs_colorrgb(gs_color *pcolor, float pr3[3])
  114. {    tri_return(pcolor->red, pcolor->green, pcolor->blue, pr3);
  115.     return 0;
  116. }
  117.  
  118. /* currentcolorspace */
  119. int
  120. gs_currentcolorspace(gs_state *pgs, gs_color_space *pcs)
  121. {    *pcs = (gs_color_space)pgs->color->space;
  122.     return 0;
  123. }
  124.  
  125. /* setscreen */
  126. int
  127. gs_setscreen(gs_state *pgs,
  128.   floatp freq, floatp angle, float (*proc)(P2(floatp, floatp)))
  129. {    gs_screen_enum senum;
  130.     gs_point pt;
  131.     int code = gs_screen_init(&senum, pgs, freq, angle);
  132.     if ( code < 0 ) return code;
  133.     while ( (code = gs_screen_currentpoint(&senum, &pt)) == 0 )
  134.         if ( (code = gs_screen_next(&senum, (*proc)(pt.x, pt.y))) < 0 )
  135.             return code;
  136.     if ( code < 0 ) return code;
  137.     pgs->ht_proc = proc;
  138.     set_phase(pgs);
  139.     return 0;
  140. }
  141.  
  142. /* currentscreen */
  143. int
  144. gs_currentscreen(gs_state *pgs,
  145.   float *pfreq, float *pangle, float (**pproc)(P2(floatp, floatp)))
  146. {    halftone *pht = pgs->halftone;
  147.     *pfreq = pht->frequency;
  148.     *pangle = pht->angle;
  149.     *pproc = pgs->ht_proc;
  150.     return 0;
  151. }
  152.  
  153. /* settransfer */
  154. /* A special entry for initialization */
  155. void
  156. gx_set_transfer_only(gs_state *pgs, gs_transfer_proc tproc)
  157. {    pgs->transfer_procs.red = pgs->transfer_procs.green =
  158.       pgs->transfer_procs.blue = pgs->transfer_procs.gray = tproc;
  159. }
  160. int
  161. gs_settransfer(gs_state *pgs, gs_transfer_proc tproc)
  162. {    gx_set_transfer_only(pgs, tproc);
  163.     return gx_remap_color(pgs);
  164. }
  165.  
  166. /* currenttransfer */
  167. gs_transfer_proc
  168. gs_currenttransfer(gs_state *pgs)
  169. {    return pgs->transfer_procs.gray;
  170. }
  171.  
  172. /* setcolortransfer */
  173. int
  174. gs_setcolortransfer(gs_state *pgs, gs_transfer_proc red_proc,
  175.   gs_transfer_proc green_proc, gs_transfer_proc blue_proc,
  176.   gs_transfer_proc gray_proc)
  177. {    pgs->transfer_procs.red = red_proc;
  178.     pgs->transfer_procs.green = green_proc;
  179.     pgs->transfer_procs.blue = blue_proc;
  180.     pgs->transfer_procs.gray = gray_proc;
  181.     return gx_remap_color(pgs);
  182. }
  183.  
  184. /* currentcolortransfer */
  185. void
  186. gs_currentcolortransfer(gs_state *pgs, gs_transfer_proc procs[4])
  187. {    procs[0] = pgs->transfer_procs.red;
  188.     procs[1] = pgs->transfer_procs.green;
  189.     procs[2] = pgs->transfer_procs.blue;
  190.     procs[3] = pgs->transfer_procs.gray;
  191. }
  192.  
  193. /* sethalftonephase */
  194. int
  195. gs_sethalftonephase(gs_state *pgs, int x, int y)
  196. {    pgs->ht_phase.x = x;
  197.     pgs->ht_phase.y = y;
  198.     set_phase(pgs);
  199.     return 0;
  200. }
  201.  
  202. /* currenthalftonephase */
  203. int
  204. gs_currenthalftonephase(gs_state *pgs, gs_int_point *pphase)
  205. {    *pphase = pgs->ht_phase;
  206.     return 0;
  207. }
  208.  
  209. /* ------ Halftone sampling ------ */
  210.  
  211. /* Set up for halftone sampling */
  212. int
  213. gs_screen_init(gs_screen_enum *penum, gs_state *pgs,
  214.   floatp freq, floatp angle)
  215. {    int cwidth, cheight;
  216.     int code;
  217.     ht_bit *order;
  218.     if ( freq < 0 ) return_error(gs_error_rangecheck);
  219.     /* Convert the frequency to cell width and height */
  220.        {    float cell_size = 72.0 / freq;
  221.         gs_point pcwh;
  222.         gs_matrix imat;
  223.         int dev_w, dev_h;
  224.         gs_deviceparams(gs_currentdevice(pgs), &imat, &dev_w, &dev_h);
  225.         if ( (code = gs_distance_transform(cell_size, cell_size,
  226.                            &imat, &pcwh)) < 0
  227.             ) return code;
  228.         /* It isn't clear to me whether we should round the */
  229.         /* width and height, truncate them, or do something */
  230.         /* more complicated.  All the problems arise from devices */
  231.         /* whose X and Y resolutions aren't the same: */
  232.         /* the halftone model isn't really designed for this. */
  233.         /* For the moment, truncate and hope for the best. */
  234. #define abs_round(z) (z < 0 ? -(int)(z) : (int)(z))
  235. /*#define abs_round(z) (z < 0 ? -(int)(z - 0.5) : (int)(z + 0.5))*/
  236.         cwidth = abs_round(pcwh.x);
  237.         cheight = abs_round(pcwh.y);
  238. #undef abs_round
  239.        }
  240.     if ( cwidth == 0 ) cwidth = 1;
  241.     if ( cheight == 0 ) cheight = 1;
  242.     if ( cwidth > max_ushort / cheight )
  243.         return_error(gs_error_rangecheck);
  244.     order = (ht_bit *)gs_malloc(cwidth * cheight, sizeof(ht_bit),
  245.                     "halftone samples");
  246.     if ( order == 0 ) return_error(gs_error_VMerror);
  247.     penum->freq = freq;
  248.     penum->angle = angle;
  249.     penum->order = order;
  250.     penum->width = cwidth;
  251.     penum->height = cheight;
  252.     penum->x = penum->y = 0;
  253.     penum->pgs = pgs;
  254.     /* The transformation matrix must include normalization to the */
  255.     /* interval (-1..1), and rotation by the negative of the angle. */
  256.        {    float xscale = 2.0 / cwidth;
  257.         float yscale = 2.0 / cheight;
  258.         gs_matrix mat;
  259.         gs_make_identity(&mat);
  260.         mat.xx = xscale;
  261.         mat.yy = yscale;
  262.         mat.tx = xscale * 0.5 - 1.0;
  263.         mat.ty = yscale * 0.5 - 1.0;
  264.         if ( (code = gs_matrix_rotate(&mat, -angle, &penum->mat)) < 0 )
  265.             return code;
  266. #ifdef DEBUG
  267. if ( gs_debug['h'] )
  268.     dprintf8("[h]Screen: w=%d h=%d [%f %f %f %f %f %f]\n",
  269.          cwidth, cheight, penum->mat.xx, penum->mat.xy,
  270.          penum->mat.yx, penum->mat.yy, penum->mat.tx, penum->mat.ty);
  271. #endif
  272.        }
  273.     return 0;
  274. }
  275.  
  276. /* Report current point for sampling */
  277. private int gx_screen_finish(P1(gs_screen_enum *));
  278. int
  279. gs_screen_currentpoint(gs_screen_enum *penum, gs_point *ppt)
  280. {    gs_point pt;
  281.     int code;
  282.     if ( penum->y >= penum->height )    /* all done */
  283.         return gx_screen_finish(penum);
  284.     if ( (code = gs_point_transform((floatp)penum->x, (floatp)penum->y, &penum->mat, &pt)) < 0 )
  285.         return code;
  286.     if ( pt.x < -1.0 ) pt.x += 2.0;
  287.     else if ( pt.x > 1.0 ) pt.x -= 2.0;
  288.     if ( pt.y < -1.0 ) pt.y += 2.0;
  289.     else if ( pt.y > 1.0 ) pt.y -= 2.0;
  290.     *ppt = pt;
  291.     return 0;
  292. }
  293.  
  294. /* Record next halftone sample */
  295. int
  296. gs_screen_next(gs_screen_enum *penum, floatp value)
  297. {    ushort sample;
  298.     ht_bit *order = penum->order;
  299.     if ( value < -1.0 || value > 1.0 )
  300.       return_error(gs_error_rangecheck);
  301.     sample = (ushort)(value * (float)(int)(max_ushort >> 1)) +
  302.            (max_ushort >> 1);
  303. #ifdef DEBUG
  304. if ( gs_debug['h'] )
  305.    {    gs_point pt;
  306.     gs_screen_currentpoint(penum, &pt);
  307.     dprintf6("[h]sample x=%d y=%d (%f,%f): %f -> %u\n",
  308.          penum->x, penum->y, pt.x, pt.y, value, sample);
  309.    }
  310. #endif
  311.     order[penum->y * penum->width + penum->x].mask = sample;
  312.     if ( ++(penum->x) >= penum->width )
  313.         penum->x = 0, ++(penum->y);
  314.     return 0;
  315. }
  316.  
  317. /* All points have been sampled. */
  318. /* Finish constructing the halftone. */
  319. private int
  320. gx_screen_finish(gs_screen_enum *penum)
  321. {    ht_bit *order = penum->order;
  322.     uint size = penum->width * penum->height;
  323.     uint i;
  324.     int code;
  325.     halftone *pht;
  326.     /* Label each element with its ordinal position. */
  327.     for ( i = 0; i < size; i++ )
  328.         order[i].offset = i;
  329.     /* Sort the samples in increasing order by value. */
  330.     gx_sort_ht_order(order, size);
  331.     /* Set up the actual halftone description. */
  332.     code = gx_ht_construct_order(penum->order, penum->width, penum->height);
  333.     if ( code < 0 ) return code;
  334.     pht = penum->pgs->halftone;
  335.     pht->frequency = penum->freq;
  336.     pht->angle = penum->angle;
  337.     pht->width = penum->width;
  338.     pht->height = penum->height;
  339.     pht->order = penum->order;
  340.     pht->order_size = pht->width * pht->height;
  341.     return 1;            /* all done */
  342. }
  343.  
  344. /* ------ Internal routines ------ */
  345.  
  346. /* Get 3 real parameters in the range [0..1], */
  347. /* and convert them to color_params. */
  348. private void
  349. tri_param(floatp p1, floatp p2, floatp p3, color_param pq3[3])
  350. {    pq3[0] = gx_unit_param(p1) * max_color_param;
  351.     pq3[1] = gx_unit_param(p2) * max_color_param;
  352.     pq3[2] = gx_unit_param(p3) * max_color_param;
  353. }
  354.  
  355. /* Convert 3 color_params to reals */
  356. private void
  357. tri_return(color_param p1, color_param p2, color_param p3, float pr3[3])
  358. {    pr3[0] = p1 / (float)max_color_param;
  359.     pr3[1] = p2 / (float)max_color_param;
  360.     pr3[2] = p3 / (float)max_color_param;
  361. }
  362.  
  363. /* Compute the negated halftone phase mod the tile size. */
  364. /* This is the displacement of the tile relative to the device coordinates. */
  365. private void
  366. set_phase(gs_state *pgs)
  367. {    halftone *pht = pgs->halftone;
  368.     if ( pht->width == 0 )
  369.         pgs->phase_mod.x = 0;
  370.     else
  371.        {    if ( (pgs->phase_mod.x = -pgs->ht_phase.x % pht->width) < 0 )
  372.             pgs->phase_mod.x += pht->width;
  373.        }
  374.     if ( pht->height == 0 )
  375.         pgs->phase_mod.y = 0;
  376.     else
  377.        {    if ( (pgs->phase_mod.y = -pgs->ht_phase.y % pht->height) < 0 )
  378.             pgs->phase_mod.y += pht->height;
  379.        }
  380. }
  381.